use crate::common::{AppState, Response};
use crate::error::AppError;
use crate::models::user::User;
use crate::vo::user::{UserLoginReqVo, UserReqVo};
use crate::vo::ValidatedJson;
use axum::extract::{Request, State};
use axum::response::IntoResponse;
use std::sync::Arc;
use tokio::sync::broadcast;

pub async fn register(
    State(app): State<Arc<AppState>>,
    ValidatedJson(user): ValidatedJson<UserReqVo>,
) -> Result<impl IntoResponse, AppError> {
    let u: User = user.into();
    User::create(u, &app.pool).await?;
    Ok(Response::ok("success"))
}

#[utoipa::path(
    post,
    path = "/api/sign",
    responses(
        (status = 200, description = "User signed in", body = String),
    )
)]
pub async fn sign(
    State(app): State<Arc<AppState>>,
    ValidatedJson(user_login_req_vo): ValidatedJson<UserLoginReqVo>,
) -> Result<impl IntoResponse, AppError> {
    let user = User::verify_email_and_password(
        user_login_req_vo.email.as_str(),
        user_login_req_vo.password.as_str(),
        &app.pool,
    )
    .await?;
    if user.is_some() {
        let user = user.unwrap();
        let id = user.id as u64;
        let token = app.ek.generate_token(user)?;
        let (tx, _rx) = broadcast::channel(255);
        app.users.clone().insert(id, tx);
        Ok(Response::ok(token))
    } else {
        Err(AppError::AuthorityError(
            "Invalid email or password".to_string(),
        ))
    }
}

pub async fn signup(mut req: Request) -> &'static str {
    let user = req.extensions_mut().get::<User>().unwrap();
    println!("{user:?}");
    "Hello, World!"
}
